package session

import (
	"encoding/json"
	"github.com/garyburd/redigo/redis"
	"sync"
)


type RedisSession struct {
	pool       *redis.Pool
	id         string
	sessionMap map[string]interface{}
	rwMutex    sync.RWMutex
	flag       int
}

func NewRedisSession(id string, pool *redis.Pool) *RedisSession {
	return &RedisSession{
		pool:       pool,
		id:         "",
		sessionMap: nil,
		rwMutex:    sync.RWMutex{},
		flag:       0,
	}
}

func (r *RedisSession)GetId() string {
	return r.id
}

func (r *RedisSession)IsModify() bool{
	return r.flag == sessionFlagModify
}

func (r *RedisSession) Set(key string, value interface{}) error {
	r.rwMutex.Lock()
	defer r.rwMutex.Unlock()
	r.sessionMap[key] = value
	r.flag = sessionFlagModify
	return nil
}

func (r *RedisSession) Save() (err error) {
	r.rwMutex.Lock()
	defer r.rwMutex.Unlock()
	if r.flag != sessionFlagModify {
		return
	}
	data, err := json.Marshal(r.sessionMap)
	if err != nil {
		return
	}
	conn := r.pool.Get()
	_, err = conn.Do("SET", r.id, data)
	return
}

func (r *RedisSession) Get(key string) (value interface{}, err error) {
	r.rwMutex.RLock()
	defer r.rwMutex.Unlock()
	if r.flag == sessionFlagNone {
		err = r.loadFromRedis()
		if err != nil {
			return
		}
	}
	value, ok := r.sessionMap[key]
	if !ok {
		err = ErrSessionKeyNotExist
	}
	return
}

func (r *RedisSession) Del(key string) error {
	r.rwMutex.Lock()
	defer r.rwMutex.Unlock()
	r.flag = sessionFlagModify
	delete(r.sessionMap, key)
	return nil
}

func (r *RedisSession) loadFromRedis() (err error) {
	conn := r.pool.Get()
	reply, err := conn.Do("GET", r.id)
	if err != nil {
		return
	}
	data, err := redis.String(reply, err)
	err = json.Unmarshal([]byte(data), &r.sessionMap)
	return
}
